package org.zjt.deepjvm;

import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Dispatcher;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import static sun.misc.VM.maxDirectMemory;

public class HeapOOM {

    //-Xms20m  -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
    public static void TestHeapOOM() {
        List<byte[]> list  = new ArrayList<>();
        int cnt = 0;
        while (true) {
            list.add(new byte[1025]);
            System.out.println(cnt++);
        }
    }


    public static class BaseFlyer{

    }

    /**
     * 在元数据区无限创建class，导致 oom。
     *
     * string.intern() 不会存放到元数据区的。
     *
     * -XX:MetaspaceSize=5M -XX:MaxMetaspaceSize=7M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\oom.dump
     */
    public static void TestPermOOM() {
        System.out.println("Let us do it now.....");
        for(int i=0;i<100000;i++){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(BaseFlyer.class);
            enhancer.setCallbackTypes(new Class[] {Dispatcher.class, MethodInterceptor.class });
            enhancer.setCallbackFilter(method -> 1);
            Class clazz = enhancer.createClass();
          //  System.out.println("Time:" + System.currentTimeMillis());
        }
    }

    //每个线程的栈容量只由-Xss参数设定。当创建该线程后，就会为该线程在内存中分配一个xss的栈区，当该线程中的函数压栈超过这个数字，就会stack异常。
    public static void TestStackOOM() {
        int cnt = 0;
        while (true) {
            TestStackOOM();
            System.out.println(cnt++);
        }
    }




    /**
     * 每个线程的栈容量只由-Xss参数设定，当创建该线程后，就会为该线程在内存中分配一个xss的栈区。
     *     OutOfMemoryError: unable to create new native thread
     *     栈区不能建立xss，使用jstack得到线程。
     *
     * (总栈区不够了)
     * 解决方案：
     *      1、减少线程数
     *      2、减少堆最大内存
     *      3、减少线程的xss
     *      4、增加进程内存
     *
     */
    public static void TestMOOM() {
        int cnt = 0;
        while (true) {
           new Thread(() -> {
               System.out.println("sssss");
               try {
                   Thread.sleep(200000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }).start();
        }
    }

    /**
     * -Xmx20M  -XX:MaxDirectMemorySize=10M
     */
    public static final int _1MB = 10 << 20;
    public static void DirectOOM() throws IllegalAccessException {
        System.out.println(maxDirectMemory());
        Field unsafeField= Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe=(Unsafe)unsafeField.get(null);
        while(true){
            unsafe.allocateMemory(_1MB);
        }
    }

    public static void main(String[] args) throws IllegalAccessException {
        TestHeapOOM();
    }
}
